package com.acpt.filter;

import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.acpt.common.CacheConstants;
import com.acpt.entity.LoginUser;
import lombok.extern.log4j.Log4j2;
import net.logstash.logback.encoder.org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import com.acpt.service.TokenService;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

@Component
@Log4j2
public class JWTAuthenticationFilter extends OncePerRequestFilter {
  private static final String TOKEN_ILLEGAL = "40001";
  private static final String TOKEN_KICK = "40002";
  private static final String TOKEN_INVALID = "40003";
  @Autowired
  private TokenService tokenService;

  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    // 获取当前请求的uri
    String uri = request.getRequestURI();
    log.info("请求路径:" + uri);
    // 判断是否是认证请求路径
    // 是：直接放行
    if (uri.contains("/doc.html") || uri.contains("/webjars") || uri.contains("/v3/api-docs")) {
      filterChain.doFilter(request, response);
      return;
    }
    // 否：获取请求头中携带的token
    String authorization = request.getHeader("Authorization");
    log.info("携带authorization:" + authorization);
    // 判断是否携带token
    // 否：抛出异常
    if (StringUtils.isBlank(authorization)) {
      request.setAttribute(CacheConstants.TOKEN_EXCEPTION, "请登录后再操作");
      request.setAttribute(CacheConstants.TOKEN_EXCEPTION_CODE, TOKEN_ILLEGAL);
      throw new RuntimeException("无效token");
    }
    String token = authorization.replace("Bearer ", "");
    if (StringUtils.isBlank(token)) {
      request.setAttribute(CacheConstants.TOKEN_EXCEPTION, "请登录后再操作");
      request.setAttribute(CacheConstants.TOKEN_EXCEPTION_CODE, TOKEN_ILLEGAL);
      throw new RuntimeException("无效token");
    }
    try {
      // 查看token是否有效
      String userIdByToken = tokenService.getUserIdByToken(token);
      if (StringUtils.isBlank(userIdByToken)) {
        request.setAttribute(CacheConstants.TOKEN_EXCEPTION, "无效token");
        request.setAttribute(CacheConstants.TOKEN_EXCEPTION_CODE, TOKEN_ILLEGAL);
        throw new RuntimeException("无效token");
      }
      // 根据userId获取用户信息
      LoginUser loginUser = tokenService.getUserByUserId(userIdByToken);
      if (null == loginUser) {
        request.setAttribute(CacheConstants.TOKEN_EXCEPTION, "登录已过期");
        request.setAttribute(CacheConstants.TOKEN_EXCEPTION_CODE, TOKEN_INVALID);
        throw new RuntimeException("登录已过期");
      }
      // 放行
      UsernamePasswordAuthenticationToken authenticationToken =
          new UsernamePasswordAuthenticationToken(loginUser, null, null);
      SecurityContextHolder.getContext().setAuthentication(authenticationToken);
      filterChain.doFilter(request, response);
    } catch (RuntimeException e) {
      log.error("用户信息获取失败token{}======== ", token);
      log.error("用户信息获取失败exception{}============", e);
      throw e;
    } catch (Exception e) {
      log.error("用户信息获取失败token{}========", token);
      log.error("用户信息获取失败exception{}============", e);
      request.setAttribute(CacheConstants.TOKEN_EXCEPTION, "系统错误，请联系管理员");
      request.setAttribute(CacheConstants.TOKEN_EXCEPTION_CODE, HttpStatus.INTERNAL_SERVER_ERROR);
      throw new RuntimeException("系统错误，请联系管理员");
    }
  }
}

